package com.ssky.bean.validator.core.checker;

import com.ssky.bean.validator.core.IDepExpExeHandler;
import com.ssky.bean.validator.core.IFieldValueGetHandler;
import com.ssky.bean.validator.core.Feedback;
import com.ssky.bean.validator.core.IValidatorContext;
import com.ssky.bean.validator.core.ValueExp;
import com.ssky.bean.validator.core.VldConstants;
import com.ssky.bean.validator.core.exception.VldException;
import com.ssky.bean.validator.core.rule.Field;
import com.ssky.bean.validator.core.rule.Rule;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Author: ssky
 * @Date: 2021/07/17, 2021/07/28
 * @Description: <li>一、 几个取值动作：
 * 1.（调用者传入）v值；调用者解决，传入参数。
 * 2.取出规则描述或需要比较的值（是否是有运算符？），常量值、动态取值（上下文值、对象中取值、所属属性取值、当前属性值)
 * 3.
 * <li>2.
 * <li>3.
 * <li>4.
 * <li>5.
 * <li>6.具体（子类）checker注入的属性必须以set开头且属性名称首字母大写,且类型为String。
 * <li>7.
 * <li>8.
 */
public abstract class AbstractChecker<V, L, B> implements IChecker<V, L, B> {
    private static final Logger L = LoggerFactory.getLogger(AbstractChecker.class);

    protected Field field;

    protected Rule rule;

    //依赖处理器
    private IDepExpExeHandler depExpExeHandler;

    //取值处理器
    protected IFieldValueGetHandler fieldValueGetHandler;


    /**
     * 作为条件时，当前属性如何取值
     * true--bean：标记从bean中取属性值
     * false--local：标记从属性所属local对象的取其他属性值
     */
    private boolean depScopeBeanFlag = true;

    /**
     * 是否存在依赖条件
     */
    private boolean havaDepExp = false;

    /**
     * “属性返回内容” 表达式
     * <li/>支持常量、取值表达式；不支持算术表达式
     */
    private ValueExp fbVExp;

    private static final Feedback SuccFb = new Feedback(false);

    //反馈信息，属性值为null
    private Feedback errFbDefault = null;
    //反馈信息，属性值为常量
    private Feedback errFbConstant = null;

    private String c_fbTag = null;

    @Override
    public void init() throws Exception {
        String fbvV = rule.getFbValue();

        fbVExp = ValueExp.genValueExp(fbvV);

        String depS = rule.getDepScope();
        if (VldConstants.DepScope_Bean.equals(depS)) {
            this.depScopeBeanFlag = true;
        } else if (VldConstants.DepScope_Local.equals(depS)) {
            this.depScopeBeanFlag = false;
        } else {
            throw new VldException(" 'depScope'(" + depS + ") Content that does not meet expectations!");
        }

        if (!StringUtils.isBlank(rule.getDepExp())) {
            havaDepExp = true;
            if (this.depExpExeHandler == null) {
                throw new VldException("Rule=" + getId() + " Config Error ; Dependencies have no corresponding IDepExpExeHandler instance!");
            }
        }

        String c_fbTag = null;
        if (rule.getFbTag() == null) {
            c_fbTag = field.getName();
        }

        if (fbVExp.isNull()) {
            errFbDefault = new Feedback(true, this.rule.getErrCode(), this.rule.getErrMsg(), c_fbTag, null);
        } else if (fbVExp.isConstant()) {
            errFbConstant = new Feedback(true, this.rule.getErrCode(), this.rule.getErrMsg(), c_fbTag, fbVExp.vExp);
        }

        initz();
    }

    abstract void initz() throws Exception;

    /**
     * 规则执行器
     *
     * @param v   规则校验的当前值
     * @param l   当前值作为属性的所在对象
     * @param b   当前值所在的顶级javaBean对象
     * @param ctx 上下文（针对具体规则的实现需求预设置内容；可基于接口IValidatorContext扩展）
     * @return
     */
    @Override
    public Feedback check(V v, L l, B b, IValidatorContext ctx) {
        if (havaDepExp) {//存在依赖
            boolean depRst = false;
            try {
                depRst = this.depExpExeHandler.exe(l, b, ctx);
            } catch (Exception e) {
                if (L.isWarnEnabled()) {
                    L.warn("ruleId=" + this.rule.getId(), e);
                }
                e.printStackTrace();
                throw new VldException(e.getMessage());
            }
            if (!depRst) {
                return SuccFb;
            }
        }

        try {
            boolean rst = this.process(v, l, b, ctx);
            if (rst) {
                return SuccFb;
            }
        } catch (Exception e) {
            L.error("Rule：" + getId() + " process Exception!", e);
            throw e;
        }
        if (fbVExp.isNull()) {
            return errFbDefault;
        } else if (fbVExp.isSelf()) {
            if (v != null) {
                return new Feedback(true, rule.getErrCode(), rule.getErrMsg(), c_fbTag, v.toString());
            } else {
                return errFbDefault;
            }
        } else if (fbVExp.isConstant()) {
            return errFbConstant;
        } else if (fbVExp.isThis()) {
            Object fv = fieldValueGetHandler.getThisFv(field.getName(), v);
            if (fv != null) {
                return new Feedback(true, rule.getErrCode(), rule.getErrMsg(), c_fbTag, fv.toString());
            } else {
                return errFbDefault;
            }
        } else if (fbVExp.isLocal()) {
            Object fv = fieldValueGetHandler.getLocalFv(field.getName(), l);
            if (fv != null) {
                return new Feedback(true, rule.getErrCode(), rule.getErrMsg(), c_fbTag, fv.toString());
            } else {
                return errFbDefault;
            }
        } else if (fbVExp.isBean()) {
            Object fv = fieldValueGetHandler.getFfv(field.getFullName(), b);
            if (fv != null) {
                return new Feedback(true, rule.getErrCode(), rule.getErrMsg(), c_fbTag, fv.toString());
            } else {
                return errFbDefault;
            }
        } else {
            return errFbDefault;
        }
    }

    /**
     * 规则作为条件时的执行器
     * <li/> 参数中为什么没有当前值，因为作为被依赖时，没法直接确定值。需要间接获取值
     *
     * @param l
     * @param b
     * @param ctx 上下文（针对具体规则的实现要求，可基于接口IValidatorContext扩展）
     * @return
     */
    @Override
    public boolean exeCondition(L l, B b, IValidatorContext ctx) {
        V v = null;
        if (depScopeBeanFlag) {
            try {
                v = (V) fieldValueGetHandler.getFfv(this.field.getFullName(), b);
            } catch (Exception e) {
                L.error("getValueByFullName err: ruleId=" + this.getId() + "; beanClass =" + field.getBeanClassType().getName() + "; fieldFullName=" + this.field.getFullName(), e);
                e.printStackTrace();
                throw new VldException(e.getMessage());
            }
        } else {
            try {
                v = (V) fieldValueGetHandler.getLocalFv(this.field.getName(), l);
            } catch (Exception e) {
                L.error("getValueByLocalName err: ruleId=" + this.getId() + "; beanClass =" + field.getPreField().getBeanClassType() + "; fieldFullName=" + this.field.getFullName(), e);
                e.printStackTrace();
                throw new VldException(e.getMessage());
            }
        }
        boolean rst = process(v, l, b, ctx);
        return rst;
    }

    /**
     * 具体规则执行器
     *
     * @param v   规则校验的当前值
     * @param l   当前值作为属性的所在对象
     * @param b   当前值所在的顶级javaBean对象
     * @param ctx 上下文（针对具体规则的实现要求，可基于接口IValidatorContext扩展）
     * @return 校验通过返回true, 不通过返回false
     */
    public abstract boolean process(V v, L l, B b, IValidatorContext ctx);

    /**
     * bean规则描述文档中唯一的ruleId
     *
     * @return
     */
    @Override
    public String getId() {
        return this.rule.getId();
    }

    public Field getField() {
        return field;
    }

    public void setField(Field field) {
        this.field = field;
    }

    public Rule getRule() {
        return rule;
    }

    public void setRule(Rule rule) {
        this.rule = rule;
    }

    public IFieldValueGetHandler getFieldValueGetHandler() {
        return fieldValueGetHandler;
    }

    public void setFieldValueGetHandler(IFieldValueGetHandler fieldValueGetHandler) {
        this.fieldValueGetHandler = fieldValueGetHandler;
    }

    public IDepExpExeHandler getDepExpExeHandler() {
        return depExpExeHandler;
    }

    public void setDepExpExeHandler(IDepExpExeHandler depExpExeHandler) {
        this.depExpExeHandler = depExpExeHandler;
    }
}
